home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Skunkware 5
/
Skunkware 5.iso
/
src
/
X11
/
xpaint-2.1.1
/
rw
/
libpnmrw.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-06-21
|
29KB
|
1,383 lines
/* libpnmrw.c - PBM/PGM/PPM read/write library
**
** Copyright (C) 1988, 1989, 1991, 1992 by Jef Poskanzer.
**
** Permission to use, copy, modify, and distribute this software and its
** documentation for any purpose and without fee is hereby granted, provided
** that the above copyright notice appear in all copies and that both that
** copyright notice and this permission notice appear in supporting
** documentation. This software is provided "as is" without express or
** implied warranty.
*/
#if defined(SVR2) || defined(SVR3) || defined(SVR4)
#ifndef SYSV
#define SYSV
#endif
#endif
#if ! ( defined(BSD) || defined(SYSV) || defined(MSDOS) )
/* CONFIGURE: If your system is >= 4.2BSD, set the BSD option; if you're a
** System V site, set the SYSV option; and if you're IBM-compatible, set
** MSDOS. If your compiler is ANSI C, you're probably better off setting
** SYSV - all it affects is string handling.
*/
/* #define BSD */
#define SYSV
/* #define MSDOS */
#endif
#include <stdio.h>
#include "libpnmrw.h"
#ifdef SYSV
#if !defined(sco)
#include <string.h>
#define rindex(s,c) strrchr(s,c)
#endif
#else /*SYSV*/
#include <strings.h>
#endif /*SYSV*/
void *malloc(int);
void free(void *);
/* Definitions. */
#define pbm_allocarray( cols, rows ) ((bit**) pm_allocarray( cols, rows, sizeof(bit) ))
#define pbm_allocrow( cols ) ((bit*) pm_allocrow( cols, sizeof(bit) ))
#define pbm_freearray( bits, rows ) pm_freearray( (char**) bits, rows )
#define pbm_freerow( bitrow ) pm_freerow( (char*) bitrow )
#define pgm_allocarray( cols, rows ) ((gray**) pm_allocarray( cols, rows, sizeof(gray) ))
#define pgm_allocrow( cols ) ((gray*) pm_allocrow( cols, sizeof(gray) ))
#define pgm_freearray( grays, rows ) pm_freearray( (char**) grays, rows )
#define pgm_freerow( grayrow ) pm_freerow( (char*) grayrow )
#define ppm_allocarray( cols, rows ) ((pixel**) pm_allocarray( cols, rows, sizeof(pixel) ))
#define ppm_allocrow( cols ) ((pixel*) pm_allocrow( cols, sizeof(pixel) ))
#define ppm_freearray( pixels, rows ) pm_freearray( (char**) pixels, rows )
#define ppm_freerow( pixelrow ) pm_freerow( (char*) pixelrow )
/* Variables. */
static char* progname;
/* Variable-sized arrays. */
char*
pm_allocrow( cols, size )
int cols;
int size;
{
register char* itrow;
itrow = (char*) malloc( cols * size );
if ( itrow == (char*) 0 )
{
(void) fprintf(
stderr, "%s: out of memory allocating a row\n", progname );
return (char*) 0;
}
return itrow;
}
void
pm_freerow( itrow )
char* itrow;
{
free( itrow );
}
char**
pm_allocarray( cols, rows, size )
int cols, rows;
int size;
{
char** its;
int i;
its = (char**) malloc( rows * sizeof(char*) );
if ( its == (char**) 0 )
{
(void) fprintf(
stderr, "%s: out of memory allocating an array\n", progname );
return (char**) 0;
}
its[0] = (char*) malloc( rows * cols * size );
if ( its[0] == (char*) 0 )
{
(void) fprintf(
stderr, "%s: out of memory allocating an array\n", progname );
free( (char*) its );
return (char**) 0;
}
for ( i = 1; i < rows; ++i )
its[i] = &(its[0][i * cols * size]);
return its;
}
void
pm_freearray( its, rows )
char** its;
int rows;
{
free( its[0] );
free( its );
}
/* File open/close that handles "-" as stdin and checks errors. */
static void
pm_perror( reason )
char* reason;
{
extern char* sys_errlist[];
extern int errno;
char* e;
e = sys_errlist[errno];
if ( reason != 0 && reason[0] != '\0' )
(void) fprintf( stderr, "%s: %s - %s\n", progname, reason, e );
else
(void) fprintf( stderr, "%s: %s\n", progname, e );
}
FILE*
pm_openr( name )
char* name;
{
FILE* f;
if ( strcmp( name, "-" ) == 0 )
f = stdin;
else
{
#ifdef MSDOS
f = fopen( name, "rb" );
#else /*MSDOS*/
f = fopen( name, "r" );
#endif /*MSDOS*/
if ( f == NULL )
{
pm_perror( name );
return (FILE*) 0;
}
}
return f;
}
FILE*
pm_openw( name )
char* name;
{
FILE* f;
#ifdef MSDOS
f = fopen( name, "wb" );
#else /*MSDOS*/
f = fopen( name, "w" );
#endif /*MSDOS*/
if ( f == NULL )
{
pm_perror( name );
return (FILE*) 0;
}
return f;
}
int
pm_closer( f )
FILE* f;
{
if ( ferror( f ) )
{
(void) fprintf(
stderr, "%s: a file read error occurred at some point\n",
progname );
return -1;
}
if ( f != stdin )
if ( fclose( f ) != 0 )
{
pm_perror( "fclose" );
return -1;
}
return 0;
}
int
pm_closew( f )
FILE* f;
{
fflush( f );
if ( ferror( f ) )
{
(void) fprintf(
stderr, "%s: a file write error occurred at some point\n",
progname );
return -1;
}
if ( f != stdout )
if ( fclose( f ) != 0 )
{
pm_perror( "fclose" );
return -1;
}
return 0;
}
static int
pbm_getc( file )
FILE* file;
{
register int ich;
ich = getc( file );
if ( ich == EOF )
{
(void) fprintf( stderr, "%s: EOF / read error\n", progname );
return EOF;
}
if ( ich == '#' )
{
do
{
ich = getc( file );
if ( ich == EOF )
{
(void) fprintf( stderr, "%s: EOF / read error\n", progname );
return EOF;
}
}
while ( ich != '\n' && ich != '\r' );
}
return ich;
}
static bit
pbm_getbit( file )
FILE* file;
{
register int ich;
do
{
ich = pbm_getc( file );
if ( ich == EOF )
return -1;
}
while ( ich == ' ' || ich == '\t' || ich == '\n' || ich == '\r' );
if ( ich != '0' && ich != '1' )
{
(void) fprintf(
stderr, "%s: junk in file where bits should be\n", progname );
return -1;
}
return ( ich == '1' ) ? 1 : 0;
}
static int
pbm_readmagicnumber( file )
FILE* file;
{
int ich1, ich2;
ich1 = getc( file );
if ( ich1 == EOF )
{
(void) fprintf(
stderr, "%s: EOF / read error reading magic number\n", progname );
return -1;
}
ich2 = getc( file );
if ( ich2 == EOF )
{
(void) fprintf(
stderr, "%s: EOF / read error reading magic number\n", progname );
return -1;
}
return ich1 * 256 + ich2;
}
static int
pbm_getint( file )
FILE* file;
{
register char ich;
register int i;
do
{
ich = pbm_getc( file );
if ( ich == EOF )
return -1;
}
while ( ich == ' ' || ich == '\t' || ich == '\n' || ich == '\r' );
if ( ich < '0' || ich > '9' )
{
(void) fprintf(
stderr, "%s: junk in file where an integer should be\n", progname );
return -1;
}
i = 0;
do
{
i = i * 10 + ich - '0';
ich = pbm_getc( file );
if ( ich == EOF )
return -1;
}
while ( ich >= '0' && ich <= '9' );
return i;
}
static int
pbm_readpbminitrest( file, colsP, rowsP )
FILE* file;
int* colsP;
int* rowsP;
{
/* Read size. */
*colsP = pbm_getint( file );
*rowsP = pbm_getint( file );
if ( *colsP == -1 || *rowsP == -1 )
return -1;
return 0;
}
static int
pbm_getrawbyte( file )
FILE* file;
{
register int iby;
iby = getc( file );
if ( iby == EOF )
{
(void) fprintf( stderr, "%s: EOF / read error\n", progname );
return -1;
}
return iby;
}
static int
pbm_readpbmrow( file, bitrow, cols, format )
FILE* file;
bit* bitrow;
int cols, format;
{
register int col, bitshift, b;
register int item;
register bit* bP;
switch ( format )
{
case PBM_FORMAT:
for ( col = 0, bP = bitrow; col < cols; ++col, ++bP )
{
b = pbm_getbit( file );
if ( b == -1 )
return -1;
*bP = b;
}
break;
case RPBM_FORMAT:
bitshift = -1;
for ( col = 0, bP = bitrow; col < cols; ++col, ++bP )
{
if ( bitshift == -1 )
{
item = pbm_getrawbyte( file );
if ( item == -1 )
return -1;
bitshift = 7;
}
*bP = ( item >> bitshift ) & 1;
--bitshift;
}
break;
default:
(void) fprintf( stderr, "%s: can't happen\n", progname );
return -1;
}
return 0;
}
static void
pbm_writepbminit( file, cols, rows, forceplain )
FILE* file;
int cols, rows;
int forceplain;
{
if ( ! forceplain )
(void) fprintf(
file, "%c%c\n%d %d\n", PBM_MAGIC1, RPBM_MAGIC2, cols, rows );
else
(void) fprintf(
file, "%c%c\n%d %d\n", PBM_MAGIC1, PBM_MAGIC2, cols, rows );
}
static void
pbm_writepbmrowraw( file, bitrow, cols )
FILE* file;
bit* bitrow;
int cols;
{
register int col, bitshift;
register unsigned char item;
register bit* bP;
bitshift = 7;
item = 0;
for ( col = 0, bP = bitrow; col < cols; ++col, ++bP )
{
if ( *bP )
item += 1 << bitshift;
--bitshift;
if ( bitshift == -1 )
{
(void) putc( item, file );
bitshift = 7;
item = 0;
}
}
if ( bitshift != 7 )
(void) putc( item, file );
}
static void
pbm_writepbmrowplain( file, bitrow, cols )
FILE* file;
bit* bitrow;
int cols;
{
register int col, charcount;
register bit* bP;
charcount = 0;
for ( col = 0, bP = bitrow; col < cols; ++col, ++bP )
{
if ( charcount >= 70 )
{
(void) putc( '\n', file );
charcount = 0;
}
putc( *bP ? '1' : '0', file );
++charcount;
}
(void) putc( '\n', file );
}
static void
pbm_writepbmrow( file, bitrow, cols, forceplain )
FILE* file;
bit* bitrow;
int cols;
int forceplain;
{
if ( ! forceplain )
pbm_writepbmrowraw( file, bitrow, cols );
else
pbm_writepbmrowplain( file, bitrow, cols );
}
static int
pgm_readpgminitrest( file, colsP, rowsP, maxvalP )
FILE* file;
int* colsP;
int* rowsP;
gray* maxvalP;
{
int maxval;
/* Read size. */
*colsP = pbm_getint( file );
*rowsP = pbm_getint( file );
if ( *colsP == -1 || *rowsP == -1 )
return -1;
/* Read maxval. */
maxval = pbm_getint( file );
if ( maxval == -1 )
return -1;
if ( maxval > PGM_MAXMAXVAL )
{
(void) fprintf( stderr, "%s: maxval is too large\n", progname );
return -1;
}
*maxvalP = maxval;
return 0;
}
#if __STDC__
static int
pgm_readpgmrow( FILE* file, gray* grayrow, int cols, gray maxval, int format )
#else /*__STDC__*/
static int
pgm_readpgmrow( file, grayrow, cols, maxval, format )
FILE* file;
gray* grayrow;
int cols;
gray maxval;
int format;
#endif /*__STDC__*/
{
register int col, val;
register gray* gP;
switch ( format )
{
case PGM_FORMAT:
for ( col = 0, gP = grayrow; col < cols; ++col, ++gP )
{
val = pbm_getint( file );
if ( val == -1 )
return -1;
*gP = val;
}
break;
case RPGM_FORMAT:
if ( fread( grayrow, 1, cols, file ) != cols )
{
(void) fprintf( stderr, "%s: EOF / read error\n", progname );
return -1;
}
break;
default:
(void) fprintf( stderr, "%s: can't happen\n", progname );
return -1;
}
return 0;
}
#if __STDC__
static void
pgm_writepgminit( FILE* file, int cols, int rows, gray maxval, int forceplain )
#else /*__STDC__*/
static void
pgm_writepgminit( file, cols, rows, maxval, forceplain )
FILE* file;
int cols, rows;
gray maxval;
int forceplain;
#endif /*__STDC__*/
{
if ( maxval <= 255 && ! forceplain )
fprintf(
file, "%c%c\n%d %d\n%d\n", PGM_MAGIC1, RPGM_MAGIC2,
cols, rows, maxval );
else
fprintf(
file, "%c%c\n%d %d\n%d\n", PGM_MAGIC1, PGM_MAGIC2,
cols, rows, maxval );
}
static void
putus( n, file )
unsigned short n;
FILE* file;
{
if ( n >= 10 )
putus( n / 10, file );
putc( n % 10 + '0', file );
}
static int
pgm_writepgmrowraw( file, grayrow, cols, maxval )
FILE* file;
gray* grayrow;
int cols;
gray maxval;
{
if ( fwrite( grayrow, 1, cols, file ) != cols )
{
(void) fprintf( stderr, "%s: write error\n", progname );
return -1;
}
return 0;
}
static int
pgm_writepgmrowplain( file, grayrow, cols, maxval )
FILE* file;
gray* grayrow;
int cols;
gray maxval;
{
register int col, charcount;
register gray* gP;
charcount = 0;
for ( col = 0, gP = grayrow; col < cols; ++col, ++gP )
{
if ( charcount >= 65 )
{
(void) putc( '\n', file );
charcount = 0;
}
else if ( charcount > 0 )
{
(void) putc( ' ', file );
++charcount;
}
putus( (unsigned short) *gP, file );
charcount += 3;
}
if ( charcount > 0 )
(void) putc( '\n', file );
return 0;
}
#if __STDC__
static int
pgm_writepgmrow( FILE* file, gray* grayrow, int cols, gray maxval, int forceplain )
#else /*__STDC__*/
static int
pgm_writepgmrow( file, grayrow, cols, maxval, forceplain )
FILE* file;
gray* grayrow;
int cols;
gray maxval;
int forceplain;
#endif /*__STDC__*/
{
if ( maxval <= 255 && ! forceplain )
return pgm_writepgmrowraw( file, grayrow, cols, maxval );
else
return pgm_writepgmrowplain( file, grayrow, cols, maxval );
}
static int
ppm_readppminitrest( file, colsP, rowsP, maxvalP )
FILE* file;
int* colsP;
int* rowsP;
pixval* maxvalP;
{
int maxval;
/* Read size. */
*colsP = pbm_getint( file );
*rowsP = pbm_getint( file );
if ( *colsP == -1 || *rowsP == -1 )
return -1;
/* Read maxval. */
maxval = pbm_getint( file );
if ( maxval == -1 )
return -1;
if ( maxval > PPM_MAXMAXVAL )
{
(void) fprintf( stderr, "%s: maxval is too large\n", progname );
return -1;
}
*maxvalP = maxval;
return 0;
}
#if __STDC__
static int
ppm_readppmrow( FILE* file, pixel* pixelrow, int cols, pixval maxval, int format )
#else /*__STDC__*/
static int
ppm_readppmrow( file, pixelrow, cols, maxval, format )
FILE* file;
pixel* pixelrow;
int cols, format;
pixval maxval;
#endif /*__STDC__*/
{
register int col;
register pixel* pP;
register int r, g, b;
gray* grayrow;
register gray* gP;
switch ( format )
{
case PPM_FORMAT:
for ( col = 0, pP = pixelrow; col < cols; ++col, ++pP )
{
r = pbm_getint( file );
g = pbm_getint( file );
b = pbm_getint( file );
if ( r == -1 || g == -1 || b == -1 )
return -1;
PPM_ASSIGN( *pP, r, g, b );
}
break;
case RPPM_FORMAT:
grayrow = pgm_allocrow( 3 * cols );
if ( grayrow == (gray*) 0 )
return -1;
if ( fread( grayrow, 1, 3 * cols, file ) != 3 * cols )
{
(void) fprintf( stderr, "%s: EOF / read error\n", progname );
return -1;
}
for ( col = 0, gP = grayrow, pP = pixelrow; col < cols; ++col, ++pP )
{
r = *gP++;
g = *gP++;
b = *gP++;
PPM_ASSIGN( *pP, r, g, b );
}
pgm_freerow( grayrow );
break;
default:
(void) fprintf( stderr, "%s: can't happen\n", progname );
return -1;
}
return 0;
}
#if __STDC__
static void
ppm_writeppminit( FILE* file, int cols, int rows, pixval maxval, int forceplain )
#else /*__STDC__*/
static void
ppm_writeppminit( file, cols, rows, maxval, forceplain )
FILE* file;
int cols, rows;
pixval maxval;
int forceplain;
#endif /*__STDC__*/
{
if ( maxval <= 255 && ! forceplain )
fprintf(
file, "%c%c\n%d %d\n%d\n", PPM_MAGIC1, RPPM_MAGIC2,
cols, rows, maxval );
else
fprintf(
file, "%c%c\n%d %d\n%d\n", PPM_MAGIC1, PPM_MAGIC2,
cols, rows, maxval );
}
static int
ppm_writeppmrowraw( file, pixelrow, cols, maxval )
FILE* file;
pixel* pixelrow;
int cols;
pixval maxval;
{
register int col;
register pixel* pP;
gray* grayrow;
register gray* gP;
grayrow = pgm_allocrow( 3 * cols );
if ( grayrow == (gray*) 0 )
return -1;
for ( col = 0, pP = pixelrow, gP = grayrow; col < cols; ++col, ++pP )
{
*gP++ = PPM_GETR( *pP );
*gP++ = PPM_GETG( *pP );
*gP++ = PPM_GETB( *pP );
}
if ( fwrite( grayrow, 1, 3 * cols, file ) != 3 * cols )
{
(void) fprintf( stderr, "%s: write error\n", progname );
return -1;
}
pgm_freerow( grayrow );
return 0;
}
static int
ppm_writeppmrowplain( file, pixelrow, cols, maxval )
FILE* file;
pixel* pixelrow;
int cols;
pixval maxval;
{
register int col, charcount;
register pixel* pP;
register pixval val;
charcount = 0;
for ( col = 0, pP = pixelrow; col < cols; ++col, ++pP )
{
if ( charcount >= 65 )
{
(void) putc( '\n', file );
charcount = 0;
}
else if ( charcount > 0 )
{
(void) putc( ' ', file );
(void) putc( ' ', file );
charcount += 2;
}
val = PPM_GETR( *pP );
putus( val, file );
(void) putc( ' ', file );
val = PPM_GETG( *pP );
putus( val, file );
(void) putc( ' ', file );
val = PPM_GETB( *pP );
putus( val, file );
charcount += 11;
}
if ( charcount > 0 )
(void) putc( '\n', file );
return 0;
}
#if __STDC__
static int
ppm_writeppmrow( FILE* file, pixel* pixelrow, int cols, pixval maxval, int forceplain )
#else /*__STDC__*/
static int
ppm_writeppmrow( file, pixelrow, cols, maxval, forceplain )
FILE* file;
pixel* pixelrow;
int cols;
pixval maxval;
int forceplain;
#endif /*__STDC__*/
{
if ( maxval <= 255 && ! forceplain )
return ppm_writeppmrowraw( file, pixelrow, cols, maxval );
else
return ppm_writeppmrowplain( file, pixelrow, cols, maxval );
}
void
pnm_init2( pn )
char* pn;
{
/* Save program name. */
progname = pn;
}
xelval pnm_pbmmaxval = 1;
int
pnm_readpnminit( file, colsP, rowsP, maxvalP, formatP )
FILE* file;
int* colsP;
int* rowsP;
int* formatP;
xelval* maxvalP;
{
gray gmaxval;
/* Check magic number. */
*formatP = pbm_readmagicnumber( file );
if ( *formatP == -1 )
return -1;
switch ( PNM_FORMAT_TYPE(*formatP) )
{
case PPM_TYPE:
if ( ppm_readppminitrest( file, colsP, rowsP, (pixval*) maxvalP ) < 0 )
return -1;
break;
case PGM_TYPE:
if ( pgm_readpgminitrest( file, colsP, rowsP, &gmaxval ) < 0 )
return -1;
*maxvalP = (xelval) gmaxval;
break;
case PBM_TYPE:
if ( pbm_readpbminitrest( file, colsP, rowsP ) < 0 )
return -1;
*maxvalP = pnm_pbmmaxval;
break;
default:
(void) fprintf(
stderr, "%s: bad magic number - not a ppm, pgm, or pbm file\n",
progname );
return -1;
}
return 0;
}
#if __STDC__
int
pnm_readpnmrow( FILE* file, xel* xelrow, int cols, xelval maxval, int format )
#else /*__STDC__*/
int
pnm_readpnmrow( file, xelrow, cols, maxval, format )
FILE* file;
xel* xelrow;
xelval maxval;
int cols, format;
#endif /*__STDC__*/
{
register int col;
register xel* xP;
gray* grayrow;
register gray* gP;
bit* bitrow;
register bit* bP;
switch ( PNM_FORMAT_TYPE(format) )
{
case PPM_TYPE:
if ( ppm_readppmrow( file, (pixel*) xelrow, cols, (pixval) maxval, format ) < 0 )
return -1;
break;
case PGM_TYPE:
grayrow = pgm_allocrow( cols );
if ( grayrow == (gray*) 0 )
return -1;
if ( pgm_readpgmrow( file, grayrow, cols, (gray) maxval, format ) < 0 )
return -1;
for ( col = 0, xP = xelrow, gP = grayrow; col < cols; ++col, ++xP, ++gP )
PNM_ASSIGN1( *xP, *gP );
pgm_freerow( grayrow );
break;
case PBM_TYPE:
bitrow = pbm_allocrow( cols );
if ( bitrow == (bit*) 0 )
return -1;
if ( pbm_readpbmrow( file, bitrow, cols, format ) < 0 )
{
pbm_freerow( bitrow );
return -1;
}
for ( col = 0, xP = xelrow, bP = bitrow; col < cols; ++col, ++xP, ++bP )
PNM_ASSIGN1( *xP, *bP == PBM_BLACK ? 0: pnm_pbmmaxval );
pbm_freerow( bitrow );
break;
default:
(void) fprintf( stderr, "%s: can't happen\n", progname );
return -1;
}
return 0;
}
xel**
pnm_readpnm( file, colsP, rowsP, maxvalP, formatP )
FILE* file;
int* colsP;
int* rowsP;
int* formatP;
xelval* maxvalP;
{
xel** xels;
int row;
if ( pnm_readpnminit( file, colsP, rowsP, maxvalP, formatP ) < 0 )
return (xel**) 0;
xels = pnm_allocarray( *colsP, *rowsP );
if ( xels == (xel**) 0 )
return (xel**) 0;
for ( row = 0; row < *rowsP; ++row )
if ( pnm_readpnmrow( file, xels[row], *colsP, *maxvalP, *formatP ) < 0 )
{
pnm_freearray( xels, *rowsP );
return (xel**) 0;
}
return xels;
}
#if __STDC__
int
pnm_writepnminit( FILE* file, int cols, int rows, xelval maxval, int format, int forceplain )
#else /*__STDC__*/
int
pnm_writepnminit( file, cols, rows, maxval, format, forceplain )
FILE* file;
int cols, rows, format;
xelval maxval;
int forceplain;
#endif /*__STDC__*/
{
switch ( PNM_FORMAT_TYPE(format) )
{
case PPM_TYPE:
ppm_writeppminit( file, cols, rows, (pixval) maxval, forceplain );
break;
case PGM_TYPE:
pgm_writepgminit( file, cols, rows, (gray) maxval, forceplain );
break;
case PBM_TYPE:
pbm_writepbminit( file, cols, rows, forceplain );
break;
default:
(void) fprintf( stderr, "%s: can't happen\n", progname );
return -1;
}
return 0;
}
#if __STDC__
int
pnm_writepnmrow( FILE* file, xel* xelrow, int cols, xelval maxval, int format, int forceplain )
#else /*__STDC__*/
int
pnm_writepnmrow( file, xelrow, cols, maxval, format, forceplain )
FILE* file;
xel* xelrow;
int cols, format;
xelval maxval;
int forceplain;
#endif /*__STDC__*/
{
register int col;
register xel* xP;
gray* grayrow;
register gray* gP;
bit* bitrow;
register bit* bP;
switch ( PNM_FORMAT_TYPE(format) )
{
case PPM_TYPE:
if ( ppm_writeppmrow( file, (pixel*) xelrow, cols, (pixval) maxval, forceplain ) < 0 )
return -1;
break;
case PGM_TYPE:
grayrow = pgm_allocrow( cols );
if ( grayrow == (gray*) 0 )
return -1;
for ( col = 0, gP = grayrow, xP = xelrow; col < cols; ++col, ++gP, ++xP )
*gP = PNM_GET1( *xP );
if ( pgm_writepgmrow( file, grayrow, cols, (gray) maxval, forceplain ) < 0 )
{
pgm_freerow( grayrow );
return -1;
}
pgm_freerow( grayrow );
break;
case PBM_TYPE:
bitrow = pbm_allocrow( cols );
if ( bitrow == (bit*) 0 )
return -1;
for ( col = 0, bP = bitrow, xP = xelrow; col < cols; ++col, ++bP, ++xP )
*bP = PNM_GET1( *xP ) == 0 ? PBM_BLACK : PBM_WHITE;
pbm_writepbmrow( file, bitrow, cols, forceplain );
pbm_freerow( bitrow );
break;
default:
(void) fprintf( stderr, "%s: can't happen\n", progname );
return -1;
}
return 0;
}
#if __STDC__
int
pnm_writepnm( FILE* file, xel** xels, int cols, int rows, xelval maxval, int format, int forceplain )
#else /*__STDC__*/
int
pnm_writepnm( file, xels, cols, rows, maxval, format, forceplain )
FILE* file;
xel** xels;
xelval maxval;
int cols, rows, format;
int forceplain;
#endif /*__STDC__*/
{
int row;
if ( pnm_writepnminit( file, cols, rows, maxval, format, forceplain ) < 0 )
return -1;
for ( row = 0; row < rows; ++row )
if ( pnm_writepnmrow( file, xels[row], cols, maxval, format, forceplain ) < 0 )
return -1;
return 0;
}
/* Colormap stuff. */
#define HASH_SIZE 20023
#define ppm_hashpixel(p) ( ( ( (long) PPM_GETR(p) * 33023 + (long) PPM_GETG(p) * 30013 + (long) PPM_GETB(p) * 27011 ) & 0x7fffffff ) % HASH_SIZE )
colorhist_vector
ppm_computecolorhist( pixels, cols, rows, maxcolors, colorsP )
pixel** pixels;
int cols, rows, maxcolors;
int* colorsP;
{
colorhash_table cht;
colorhist_vector chv;
cht = ppm_computecolorhash( pixels, cols, rows, maxcolors, colorsP );
if ( cht == (colorhash_table) 0 )
return (colorhist_vector) 0;
chv = ppm_colorhashtocolorhist( cht, maxcolors );
ppm_freecolorhash( cht );
return chv;
}
void
ppm_addtocolorhist( chv, colorsP, maxcolors, colorP, value, position )
colorhist_vector chv;
pixel* colorP;
int* colorsP;
int maxcolors, value, position;
{
int i, j;
/* Search colorhist for the color. */
for ( i = 0; i < *colorsP; ++i )
if ( PPM_EQUAL( chv[i].color, *colorP ) )
{
/* Found it - move to new slot. */
if ( position > i )
{
for ( j = i; j < position; ++j )
chv[j] = chv[j + 1];
}
else if ( position < i )
{
for ( j = i; j > position; --j )
chv[j] = chv[j - 1];
}
chv[position].color = *colorP;
chv[position].value = value;
return;
}
if ( *colorsP < maxcolors )
{
/* Didn't find it, but there's room to add it; so do so. */
for ( i = *colorsP; i > position; --i )
chv[i] = chv[i - 1];
chv[position].color = *colorP;
chv[position].value = value;
++(*colorsP);
}
}
colorhash_table
ppm_computecolorhash( pixels, cols, rows, maxcolors, colorsP )
pixel** pixels;
int cols, rows, maxcolors;
int* colorsP;
{
colorhash_table cht;
register pixel* pP;
colorhist_list chl;
int col, row, hash;
cht = ppm_alloccolorhash( );
if ( cht == (colorhash_table) 0 )
return (colorhash_table) 0;
*colorsP = 0;
/* Go through the entire image, building a hash table of colors. */
for ( row = 0; row < rows; ++row )
for ( col = 0, pP = pixels[row]; col < cols; ++col, ++pP )
{
hash = ppm_hashpixel( *pP );
for ( chl = cht[hash]; chl != (colorhist_list) 0; chl = chl->next )
if ( PPM_EQUAL( chl->ch.color, *pP ) )
break;
if ( chl != (colorhist_list) 0 )
++(chl->ch.value);
else
{
if ( ++(*colorsP) > maxcolors )
{
ppm_freecolorhash( cht );
return (colorhash_table) 0;
}
chl = (colorhist_list) malloc( sizeof(struct colorhist_list_item) );
if ( chl == 0 )
{
(void) fprintf(
stderr, "%s: out of memory computing hash table\n",
progname );
ppm_freecolorhash( cht );
return (colorhash_table) 0;
}
chl->ch.color = *pP;
chl->ch.value = 1;
chl->next = cht[hash];
cht[hash] = chl;
}
}
return cht;
}
colorhash_table
ppm_alloccolorhash( )
{
colorhash_table cht;
int i;
cht = (colorhash_table) malloc( HASH_SIZE * sizeof(colorhist_list) );
if ( cht == 0 )
{
(void) fprintf(
stderr, "%s: out of memory allocating hash table\n", progname );
return (colorhash_table) 0;
}
for ( i = 0; i < HASH_SIZE; ++i )
cht[i] = (colorhist_list) 0;
return cht;
}
int
ppm_addtocolorhash( cht, colorP, value )
colorhash_table cht;
pixel* colorP;
int value;
{
register int hash;
register colorhist_list chl;
chl = (colorhist_list) malloc( sizeof(struct colorhist_list_item) );
if ( chl == 0 )
return -1;
hash = ppm_hashpixel( *colorP );
chl->ch.color = *colorP;
chl->ch.value = value;
chl->next = cht[hash];
cht[hash] = chl;
return 0;
}
colorhist_vector
ppm_colorhashtocolorhist( cht, maxcolors )
colorhash_table cht;
int maxcolors;
{
colorhist_vector chv;
colorhist_list chl;
int i, j;
/* Now collate the hash table into a simple colorhist array. */
chv = (colorhist_vector) malloc( maxcolors * sizeof(struct colorhist_item) );
/* (Leave room for expansion by caller.) */
if ( chv == (colorhist_vector) 0 )
{
(void) fprintf(
stderr, "%s: out of memory generating histogram\n", progname );
return (colorhist_vector) 0;
}
/* Loop through the hash table. */
j = 0;
for ( i = 0; i < HASH_SIZE; ++i )
for ( chl = cht[i]; chl != (colorhist_list) 0; chl = chl->next )
{
/* Add the new entry. */
chv[j] = chl->ch;
++j;
}
/* All done. */
return chv;
}
colorhash_table
ppm_colorhisttocolorhash( chv, colors )
colorhist_vector chv;
int colors;
{
colorhash_table cht;
int i, hash;
pixel color;
colorhist_list chl;
cht = ppm_alloccolorhash( );
if ( cht == (colorhash_table) 0 )
return (colorhash_table) 0;
for ( i = 0; i < colors; ++i )
{
color = chv[i].color;
hash = ppm_hashpixel( color );
for ( chl = cht[hash]; chl != (colorhist_list) 0; chl = chl->next )
if ( PPM_EQUAL( chl->ch.color, color ) )
{
(void) fprintf(
stderr, "%s: same color found twice - %d %d %d\n", progname,
PPM_GETR(color), PPM_GETG(color), PPM_GETB(color) );
ppm_freecolorhash( cht );
return (colorhash_table) 0;
}
chl = (colorhist_list) malloc( sizeof(struct colorhist_list_item) );
if ( chl == (colorhist_list) 0 )
{
(void) fprintf( stderr, "%s: out of memory\n", progname );
ppm_freecolorhash( cht );
return (colorhash_table) 0;
}
chl->ch.color = color;
chl->ch.value = i;
chl->next = cht[hash];
cht[hash] = chl;
}
return cht;
}
int
ppm_lookupcolor( cht, colorP )
colorhash_table cht;
pixel* colorP;
{
int hash;
colorhist_list chl;
hash = ppm_hashpixel( *colorP );
for ( chl = cht[hash]; chl != (colorhist_list) 0; chl = chl->next )
if ( PPM_EQUAL( chl->ch.color, *colorP ) )
return chl->ch.value;
return -1;
}
void
ppm_freecolorhist( chv )
colorhist_vector chv;
{
free( (char*) chv );
}
void
ppm_freecolorhash( cht )
colorhash_table cht;
{
int i;
colorhist_list chl, chlnext;
for ( i = 0; i < HASH_SIZE; ++i )
for ( chl = cht[i]; chl != (colorhist_list) 0; chl = chlnext )
{
chlnext = chl->next;
free( (char*) chl );
}
free( (char*) cht );
}